//
// Created by 寻欢 on 2021-10-09.
//
// 2019240004 董博阳 大数据191 实验二 进程管理

/*
 * 具体方法就是将创建的主进程设成全局变量。这样具体方法体内可以使用继承主进程的进度。
 * 然后在创建一个ThirdThreadFunc 方法，这个和SecondThreadFunc 大同小异。
 * SecondThreadFunc 中启动 然后在创建一个ThirdThreadFunc ，
 * 则使用main方法中的hThread = (HANDLE) _beginthreadex(NULL,0,&ThirdThreadFunc,NULL,0,&threadID); 将新的线程名添加。
 * 将ThirdThreadFunc 内的方法体写完就可以了。再加上那些新的提示信息。
 * 那些printf不能放到 _endthreadex 因为这个是终止线程的。
 */

#include <windows.h>
#include <stdio.h>
#include <process.h>

#define BIG_NUMBER 100000000
//HANDLE :句柄，是windows用来表示对象的（不是c++的对象）
//创建一个一个句柄变量，线程name
HANDLE hThread;

//定义线程的ID
unsigned threadID;

unsigned Counter;  //定义一个无符号的变量Counter，只能表示正数

unsigned _stdcall ThirdThreadFunc( void* pArguments ) {
    printf( "      -- In third thread. . . \n" );

    while ( Counter < BIG_NUMBER / 2)
        Counter++;

    printf("      -- End of third thread....\n");
    printf("      Counter should be %ld;it is ->%d\n",BIG_NUMBER,Counter);
    //_endthread终止由_beginthread创建的线程_endthreadex  并终止由_beginthreadex创建的线程
    _endthreadex( 0);
    return 0;
}
/*
 * 调用 __stdcall 约定用于调用Win32 API函数。 被调用者清理堆栈，以便编译器生成 vararg 函数 __cdecl 。 使用此调用约定的函数需要一个函数原型。 修饰 __stdcall 符特定于 Microsoft。
 */
unsigned _stdcall SecondThreadFunc( void* pArguments ) {
    printf( " -- In second thread. . . Creating third thread....\n" );

    hThread = (HANDLE) _beginthreadex(NULL,0,&ThirdThreadFunc,NULL,0,&threadID);
    WaitForSingleObject(hThread,INFINITE);

    while ( Counter < BIG_NUMBER )
        Counter++;

    printf(" -- End of second thread...\n");
    //_endthread终止由_beginthread创建的线程_endthreadex  并终止由_beginthreadex创建的线程
    _endthreadex( 0);
    return 0;
}
int main(){



    printf("In main thread....Creating second thread...\n");

    //Create the second thread.
    //Security :指向SECURITY_ATTRIBUTES结构的指针，该结构确定返回的句柄是否可以由子进程继承，如果Security为NULL,则不能继承句柄。必须NULL为windows 95应用程序
    //_stack_size :新线程的堆栈大小或为0
    //unsigned (__stdcall *_StartAddress) (void *)：接收创建的函数
    //ArgList:要传递到新线程的参数列表，或NULL
    //initflag: 控制新线程的初始状态的标志。 设置 initflag 为0可立即运行，或设置为以 CREATE_SUSPENDED 在挂起状态下创建线程; 使用 ResumeThread 执行线程。 设置 initflag 为 STACK_SIZE_PARAM_IS_A_RESERVATION 标志以将 stack_size 用作堆栈的初始保留大小（以字节为单位）; 如果未指定此标志，则 stack_size 指定提交大小。
    //ThrdAddr :指向接收线程标识符的32位变量。如果是NULL，则不使用。

    hThread = (HANDLE) _beginthreadex(NULL,0,&SecondThreadFunc,NULL,0,&threadID);


//    Wait until second thread terminates .If you comment out the line
//    below,Counter will not be correct because the thread has not
//    terminated,and Counter most likely has not been incremented to
//    10000000 yet

    //等待指定对象处于信号状态或超时间隔结束
    //HANDLE :对象的句柄。有关可以指定句柄的对象类型的列表，请参阅以下备注部分。
    //        如果此句柄在等待仍处于挂起状态时关闭，则函数的行为未定义。句柄必须具有SYNCHRONIZE访问权限。
    //dwMilliseconds :超时间隔，以毫秒为单位。如果指定了非零值，则函数会等待，直到对象发出信号或间隔结束。
    //                如果dwMilliseconds为零，如果对象没有发出信号，函数不会进入等待状态；它总是立即返回。
    //                如果dwMilliseconds是INFINITE，则该函数将仅在对象收到信号时返回。
    WaitForSingleObject(hThread,INFINITE);

    printf("Counter should be %ld;it is ->%d\n",BIG_NUMBER,Counter);
    printf("End of main thread....");
    //Destroy the thread object
    CloseHandle(hThread);
}
